#ifndef vir_queue_cc
#define vir_queue_cc
#include "virqueue.h"
#include "queue.h"


/* 
 * in COPE, each cope output queue maintain a table for packet queue, named
 * virtual queue, this table is keyed by neighbor id and packet type(L or S)
 */

VirQueue::~VirQueue() {
  vir_table_.clear();
  //delete vir_table_;
}

VirQueue::VirQueue () {
  //vir_table_ = new map<vir_key_t, list<Packet*> *>();      
}

void VirQueue::show() {
  
  for( int id = 0; id < 11; id++) {
    vir_key_t key;
    vir_key_t key2;
    key.nb_id = id;
    key.type = 'S';
    cout << "~~~~~~~~~~~~~~~~~~~~~~~~node " << id << " S~~~~~~~~~~~~~~~~~~~~~~" << endl;
       
    VirTableIter iter = vir_table_.find(key);
    // not exist this key's entry
    list<Packet*>::iterator it;
    if(iter == vir_table_.end()) {
      cout<< "No this entry!" << endl;
    
    } else {
      cout << "the addr is " << iter->second << endl;
      for(it = iter->second->begin(); it != iter->second->end(); it++) {
	cout<< HDR_CMN(*it)->uid_ 
	    << " " << HDR_CMN(*it)->cope_pkt_id() << "|";
      }
      cout << endl;
    }
    key2.type = 'L';
    key2.nb_id = id;
    cout << "~~~~~~~~~~~~~~~~~~~~~~~~node " << id << " L~~~~~~~~~~~~~~~~~~~~~~" << endl;
       
    VirTableIter iter2 = vir_table_.find(key2);
    // not exist this key's entry
    if(iter2 == vir_table_.end()) {
      cout<< "No this entry!" << endl;
      continue;
    }
    cout << "the addr is " << iter->second << endl;
    for(it = iter2->second->begin(); it != iter2->second->end(); it++) {
      cout<< HDR_CMN(*it)->uid_ 
    	  << " " << HDR_CMN(*it)->cope_pkt_id() << "|";
    }
    cout << endl;

  }
  
}
/*
 * rt is used to decide enque tail or head
 */
void VirQueue::enque_vir_pkt(Packet * p, bool rt) {
 
    vir_key_t key;
    key.nb_id = HDR_CMN(p)->next_hop();
    if (HDR_CMN(p)->size() < PACKET_SIZE_THRESHOLD) { //SmallVirQueue
      key.type = 'S';

    } else {
      key.type = 'L';

    }
    VirTableIter iter;
    iter = vir_table_.find(key);
    // not exist this key's entry
    if(iter == vir_table_.end()) {
      list<Packet *> * pkq = new list<Packet *>;
      vir_table_.insert(std::pair<vir_key_t, list<Packet*>* >(key, pkq));
      iter = vir_table_.find(key);
    }
    
    if( rt == false ){
        
        iter->second->push_back(p);
	// show();
    }
    else 
	iter->second->push_front(p);

    //    show();
}


/* 
 * remove a specific packet, in COPE, we usually remove the head packet
 */
void VirQueue::remove_vir_pkt(Packet * p) {
    
    if(!p || HDR_CMN(p)->next_hop() < 0)
	return;
    vir_key_t key;
    key.nb_id = HDR_CMN(p)->next_hop();

    if (HDR_CMN(p)->size() < PACKET_SIZE_THRESHOLD) { //SmallVirQueue
	key.type = 'S';
    } else {
	key.type = 'L';
    }

    VirTableIter iter;
    iter = vir_table_.find(key);
  
    // show();
    if(iter != vir_table_.end()) {
      list<Packet*>::iterator pit = iter->second->begin();
      while(pit != iter->second->end()) {
	if(HDR_CMN(*pit)->cope_pkt_id() == HDR_CMN(p)->cope_pkt_id()) {
	  iter->second->remove(*pit);
	  break;
	}
	pit++;
      }
  
	if(iter->second->empty()) {
	  vir_table_.erase(iter);
	  return;
	} 
	//	show();
      
    } 
}


/* 
 * will return null if the specific entry does not exist 
 */
list<Packet*>* VirQueue::get_vir_pktq(int nb_id, char type) {
    vir_key_t key;
    key.nb_id = nb_id;
    key.type = type;
    
    VirTableIter iter = vir_table_.find(key);
    if(iter != vir_table_.end() && !iter->second->empty()) {
	//         show();
	
	return iter->second;
    }     
    return NULL;  
}


#endif
